package com.jiangyao.common.handler;

import com.jiangyao.common.ApiResult;
import com.jiangyao.common.enums.ErrorEnum;
import com.jiangyao.common.exception.ParameterException;
import com.jiangyao.common.exception.ServerException;
import com.jiangyao.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yych
 */
@ControllerAdvice(annotations = {RestController.class, Controller.class})
public class GlobalExceptionHandler {

	private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

	@ResponseBody
	@ExceptionHandler(value = ServerException.class)
	@ResponseStatus(HttpStatus.OK)
	public ApiResult serverExceptionHandler(ServerException exception) {
		if (exception.getCode() == 403) {
			logger.error("服务器异常:{}", exception.getMessage());
		} else {
			logger.error("服务器异常:{}", exception.getMessage(), exception);
		}
		return ApiResult.error(exception.getCode(), exception.getMessage());
	}

	@ResponseBody
	@ExceptionHandler(value = ParameterException.class)
	@ResponseStatus(HttpStatus.OK)
	public ApiResult portalExceptionHandler(ParameterException exception) {
		logger.error("前端参数传入异常:{}", exception.getMessage(), exception);
		return ApiResult.error(ErrorEnum.PARAMETERS_ERROR.getResCode(), exception.getMessage());
	}


	/**
	 * 全部异常处理
	 *
	 * @param exception 异常
	 * @return 错误信息
	 */
	@ResponseBody
	@ExceptionHandler(value = Exception.class)
	@ResponseStatus(HttpStatus.OK)
	public ApiResult exceptionHandler(Exception exception) {
		logger.error("服务器异常:{}", exception.getMessage(), exception);
		return ApiResult.error(ErrorEnum.SYSTEM_ERROR.getResCode(), ErrorEnum.SYSTEM_ERROR.getResMsg());
	}


	/**
	 * HttpMessageNotReadableException异常处理：一般为请求参数
	 *
	 * @param exception 异常
	 * @return 错误信息
	 */
	@ResponseBody
	@ExceptionHandler(value = HttpMessageNotReadableException.class)
	@ResponseStatus(HttpStatus.OK)
	public ApiResult exceptionHandler(HttpMessageNotReadableException exception) {
		logger.error("前端参数传入异常:{}", exception.getMessage(), exception);
		return ApiResult.error(ErrorEnum.JSON_ERROR.getResCode(), ErrorEnum.JSON_ERROR.getResMsg());
	}

	/**
	 * 请求参数验证没通过异常处理
	 *
	 * @param exception 异常
	 * @return 结果
	 */
	@ResponseBody
	@ExceptionHandler(value = MethodArgumentNotValidException.class)
	@ResponseStatus(HttpStatus.OK)
	public ApiResult methodArgumentNotValidException(MethodArgumentNotValidException exception) {
		return ApiResult.error(ErrorEnum.PARAMETERS_ERROR.getResCode(), validRequestParams(exception.getBindingResult()));
	}

	/**
	 * 请求方式不允许
	 *
	 * @param exception 异常
	 * @return 结果
	 */
	@ResponseBody
	@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
	@ResponseStatus(HttpStatus.OK)
	public ApiResult serverExceptionHandler(HttpRequestMethodNotSupportedException exception) {
		logger.error("请求方式不允许:{}", exception.getMessage(), exception);
		return ApiResult.error(ErrorEnum.METHOD_NOT_ALLOWED.getResCode(), ErrorEnum.METHOD_NOT_ALLOWED.getResMsg());
	}

	/**
	 * 获取参数错误信息
	 *
	 * @param ApiResult 参数验证结果
	 * @return 错误信息
	 */
	private String validRequestParams(BindingResult ApiResult) {
		if (ApiResult == null) {
			return "";
		}
		if (ApiResult.hasErrors()) {
			List<ObjectError> list = ApiResult.getAllErrors();
//			StringBuilder errorMsg = new StringBuilder();
			List<String> errorMsgList = new ArrayList<>();

			for (ObjectError objectError : list) {
				FieldError error = (FieldError) objectError;
				// errorMsg.append(error.getField()).append(error.getDefaultMessage()).append(";");
				// errorMsg.append(error.getDefaultMessage()).append(";");
				if (!errorMsgList.contains(error.getDefaultMessage())) {
					errorMsgList.add(error.getDefaultMessage());
				}
			}
			return StringUtils.list2string(errorMsgList, ";");
		}
		return "";
	}
}
